﻿using System;
using System.ServiceModel.Channels;
using System.Threading.Tasks;
using System.Transactions;
using RockBus.DataContracts;
using RockBus.Messages.Interfaces;
using RockBus.Routing.Interfaces;

namespace RockBus.Routing.MessageConverters
{
    public class RoutingContext : IRoutingContext
    {
        internal RoutingContext(IMessage messageWrapper, Transaction transaction, TaskCompletionSource<Message> tcs, ExchangeTypeEnum exchangeType)
            : this(Guid.NewGuid(), messageWrapper, transaction, tcs, exchangeType)
        {
        }

        internal RoutingContext(Guid correlationId, IMessage messageWrapper, Transaction transaction, TaskCompletionSource<Message> tcs, ExchangeTypeEnum exchangeType)
        {
            this.CorrelationId = correlationId;
            this.MessageWrapper = messageWrapper;
            this.RequestMessageVersion = messageWrapper.Version;
            this.Transaction = transaction;
            this.PublisherExchangeType = exchangeType;
            this.TaskCompletionSource = tcs;
        }

        internal RoutingContext(RoutingContext routingContext)
        {
            this.CorrelationId = routingContext.CorrelationId;
            this.Transaction = routingContext.Transaction;
            this.PublisherExchangeType = routingContext.PublisherExchangeType;
            this.ContainsPersistentSubscriptions = routingContext.ContainsPersistentSubscriptions;
            this.AdvertisementInfo = routingContext.AdvertisementInfo;
            this.AdvertisedResponse = routingContext.AdvertisedResponse;
            this.TaskCompletionSource = routingContext.TaskCompletionSource;
        }

        #region IRoutingContext

        public Guid CorrelationId { get; private set; }

        public IMessage MessageWrapper { get; private set; }

        public MessageVersion RequestMessageVersion { get; private set; }

        public Transaction Transaction { get; private set; }

        public ExchangeTypeEnum PublisherExchangeType { get; private set; }

        public Task Task { get { return this.TaskCompletionSource.Task; } }

        public bool ContainsPersistentSubscriptions { get; set; }

        public AdvertisementInfo AdvertisementInfo { get; set; }

        public Message AdvertisedResponse { get; set; }

        public bool TrySetResult(IMessage response)
        {
            var responseMsg = response.MarshalMessage(this.RequestMessageVersion);
            return this.TaskCompletionSource.TrySetResult(responseMsg);
        }

        public bool TrySetResult(Message response)
        {
            return this.TaskCompletionSource.TrySetResult(response);
        }

        public bool TrySetException(Exception exc)
        {
            return this.TaskCompletionSource.TrySetException(exc);
        }

        //public bool TrySetFromRoutingContext(IRoutingContext routingContext)
        //{
        //    if (routingContext.Task.Exception != null)
        //    {
        //        return this.TrySetException(routingContext.Task.Exception);
        //    }

        //    Message responseMsg = null;
        //    if (this.AdvertisementInfo == null)
        //    {
        //        responseMsg = routingContext.MessageWrapper.MarshalMessage(this.RequestMessageVersion);
        //    }
        //    else
        //    {
        //        var response = this.PipelineManager.ExecuteOutboundResponsePipeline(routingContext.MessageWrapper, this.RoutingContext, this.AdvertisementInfo.Detail);
        //        responseMsg = response.MarshalMessage(this.RoutingContext.RequestMessageVersion);
        //    }

        //    this.RoutingContext.TaskCompletionSource.TrySetResult(responseMsg);
        //}

        #endregion

        public IRoutingContext Copy(IMessage message)
        {
            var clone = new RoutingContext(this);
            clone.MessageWrapper = message;
            clone.RequestMessageVersion = message.Version;
            return clone;
        }

        private TaskCompletionSource<Message> TaskCompletionSource { get; set; }

        public override string ToString()
        {
            return string.Format("RoutingContext: CorrelationId: {0}; Action: {1};", this.CorrelationId.ToString(), this.MessageWrapper.Action);
        }
    }
}
